package com.bootdo.ocr;
import com.alibaba.fastjson.JSON;
import com.bootdo.exception.BizException;
import com.bootdo.utils.PDFToIMGUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;

import static org.apache.commons.io.FileUtils.*;

public abstract class OcrService<F extends OcrBaseResult> implements IOcrService {

    protected  Logger logger = null;

    public static final int DPI_100 = 100;

    public static final int DPI_200 = 200;

    public static final int DPI_500 = 500;

    public static final int DPI_300 = 300;

    public static final int DPI_400 = 400;

    protected static final int POLL_TIME = 5;


    protected static Map<Integer, Integer> DPIVAL_MAP = Maps.newTreeMap();

    {
        DPIVAL_MAP.put(1, DPI_200);
        DPIVAL_MAP.put(2, DPI_100);
        DPIVAL_MAP.put(3, DPI_300);
        DPIVAL_MAP.put(4, DPI_400);
        DPIVAL_MAP.put(5, DPI_500);
    }

    public OcrService() {
         PropertyConfigurator.configure("log4j.properties");
        this.logger = Logger.getLogger(getClass());
    }

    protected String apiKey;

    protected String secretKey;

    protected String appId;
    /**
     * 国标 正则匹配
     */
    public static final String GB_PATTERN = "^GB1";

    public static final String BLANK_CHAR = " ";
    /**
     * 初始化参数
     * @param apiKey
     * @param secretKey
     * @param appId
     */
    protected abstract void init(String apiKey, String secretKey, String appId);

    protected abstract List<F> fetchOcrDataByFileUrlDTO(FileUrlDTO dto);


    /**
     * 校验是否重新处理
     * @param f 处理结果
     * @return boolean
     */
    protected abstract boolean  validateDoRepeat(F f);
    /**
     * 轮询调用api
     */
    protected abstract void roundRobinApi(FileUrlDTO dto, int pollIndex,   Map<String, F> resultMap);

    /**
     * 拷贝文件
     * @param ocrResults
     * @throws IOException
     */
    protected void cpFiles(List<F> ocrResults) throws IOException {

        for (F ocrResult : ocrResults) {
            if (ocrResult.getMatchType() == MatchType.MATCH  ||
                    ocrResult.getMatchType() == MatchType.PARTICAL) {
                ocrResult.setCorrectFilePath(
                        cpFileByPath(
                            ocrResult.getFilePath(),
                            FileType.pdf.getType(),
                            ocrResult.getCorrectFileName(),
                            ocrResult.getMatchType().getValue()
                         ));
            }
            /**
             * 如果发现不对就以编码命名
             */
            if (ocrResult.getMatchType() == MatchType.NOTMATCH) {
                ocrResult.setCorrectFilePath(
                        cpFileByPath(
                            ocrResult.getFilePath(),
                            FileType.pdf.getType(),
                            ocrResult.getCorrectFileName(),
                            ocrResult.getMatchType().getValue()
                        ));
            }
            /**
             * undo file
             */
            if (ocrResult.getMatchType() == MatchType.UNDO) {
                ocrResult.setCorrectFilePath(
                        cpFileByPath(
                                ocrResult.getFilePath(),
                                FileType.pdf.getType(),
                                ocrResult.getCorrectFileName(),
                                ocrResult.getMatchType().getValue()
                        ));
            }

        }
    }
    /**
     * 根据 目录来调用
     *
     * @param dir
     * @return
     */
    @Override
    public  List<F> validateFileByDirAndPattern(String dir, FileType fileType, String pattern, DpiType dpi) throws BizException {
        List<String> fileList = Lists.newArrayList();
        try {
            getFileUrl(dir, fileList, fileType);
        } catch (FileNotFoundException e) {
            throw new BizException(e.getMessage(), e);
        }
        FileUrlDTO fileUrlDTO = FileUrlDTO.initFilePath(fileList, pattern == null ? GB_PATTERN : pattern);
        if (fileType == FileType.pdf) {
           // 转化成 png
            fileList.forEach(filePath -> {
                fileUrlDTO.put(filePath, PDFToIMGUtil.pdf2Png(filePath, dir, dpi.getDpiVal()));
            });
        }
        List<F> list = fetchOcrDataByFileUrlDTO(fileUrlDTO);
        /**
         * 拷贝文件
         */
//        try {
//            cpFiles(list);
//        } catch (IOException e) {
//            logger.error("cp file error", e);
//        }
        /**
         * 清空生成的文件
         */
        Map<String, String> map = fileUrlDTO.getFilePathMap();
        if (fileType == FileType.pdf) {
            for(String key : map.keySet()) {
                final String pngFilePath = map.get(key);
                File pngFile = new File(pngFilePath);
                if (pngFile.exists()) {
                    pngFile.delete();
                }
            }
        }
        logger.error("validateFileByDirAndPattern result =========>>>>>>>>>>" + JSON.toJSONString(list) + "<<<<<<<<<<<<<<<<================");
        return list;
    }

    @Override
    public List<F> validateFileByDir(String dir, FileType fileType, DpiType dpi) {
        List<String> fileList = Lists.newLinkedList();
        List<F> resultList = Lists.newLinkedList();
        try{
            getFileUrl(dir, fileList, fileType);
        } catch (FileNotFoundException e) {
            throw new BizException(e.getMessage(), e);
        }
        final Map<String, HashSet<String>> stringHashSetMap = groupFiles(fileList);
        stringHashSetMap.forEach((pattern, paths) -> {
            paths.forEach(pathObj -> {
                resultList.addAll(validateFileByDirAndPattern(pathObj, FileType.pdf, pattern, dpi));
            });
        });
        logger.error("validateFileByDir result =========>>>>>>>>>>" + JSON.toJSONString(resultList) + "<<<<<<<<<<<<<<<<================");
        return resultList;
    }



    protected String cpFileByPath(String source, String format, String newFileName, String temp) throws IOException {
        File file = new File(source);
        final String fileName = file.getName();
        String newFilePath = source.replaceAll(fileName, temp + File.separator + File.separator + newFileName + "." + format);
        logger.info("source : " + source + ", desc :" + newFilePath);
        copyFile(new File(source), new File(newFilePath));
        return newFilePath;
    }

    protected  <F> F tranJsonBean(String str,  Class<F> t) {
        Gson gson = new GsonBuilder().serializeNulls().create();
        return gson.fromJson(str, t);
    }

    /**
     * 添加文件或者文件夹
     * @param path 文件路径 或者文件夹路劲
     * @param fileList 文件返回列表
     * @param fileType 文件类型
     */
    public  static void getFileUrl(String path , List<String> fileList, FileType fileType) throws FileNotFoundException {
        File file = new File(path);
        if (!file.exists()) {
            throw new FileNotFoundException();
        }
        if(file.isDirectory()) {
            File[] array = file.listFiles();
            for (int i = 0; i < array.length; i++) {
                File tempFile = array[i];
                if (tempFile.isFile()) {
                    String fileName = tempFile.getName();
                    String suffix = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
                    if (FileType.valueOf(suffix) == fileType) {
                        fileList.add(tempFile.getPath());
                    }
                }
            }
        } else {
            String fileName = file.getName();
            String suffix = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
            if (FileType.valueOf(suffix) == fileType) {
                fileList.add(file.getPath());
            }
        }
    }

    public static Map<String, HashSet<String>> groupFiles(List<String> paths) {
        Map<String, HashSet<String>> ocrFileMap = new HashMap<>();
        for (String sourcePath : paths) {
            File sourceFile = new File(sourcePath);
            String cName = sourceFile.getName();
            if(cName.contains(BLANK_CHAR)) {
                String forderName = cName.split(BLANK_CHAR)[0];
                if (!ocrFileMap.containsKey(forderName)) {
                    HashSet<String> files = new HashSet<>();
                    ocrFileMap.put(forderName, files);
                }
                ocrFileMap.get(forderName).add(sourcePath);
            }
        }
        return ocrFileMap;
    }
}
